home *** CD-ROM | disk | FTP | other *** search
/ PC Format (South-Africa) 2001 June / PCFJune.iso / mweb / MWEB Utils / ws295sdk.exe / Ws2sdkzp.exe / SAMPLES / WS2CHAT / CHATSOCK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-06  |  81.7 KB  |  2,781 lines

  1. /*++
  2.  
  3. Copyright (c) 1995 Intel Corp
  4.  
  5. Module Name:
  6.  
  7.     chatsock.c
  8.  
  9. Abstract:
  10.  
  11.     Socket-related functions for the WinSock2 Chat sample application.
  12. --*/
  13.  
  14. #include "nowarn.h"  /* turn off benign warnings */
  15. #ifndef _WINSOCKAPI_
  16. #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
  17. #endif
  18. #include <windows.h>
  19. #include <winsock2.h>
  20. #include "nowarn.h"  /* some warnings may have been turned back on */
  21. #include <stdlib.h>
  22. #include <malloc.h>
  23. #include <stdio.h>
  24. #include <assert.h>
  25. #include <ws2atm.h>
  26. #include "ws2chat.h"
  27. #include "chatsock.h"
  28. #include "chatdlg.h"
  29.  
  30.  
  31.  
  32. //
  33. // Static Globals
  34. //
  35.  
  36. // points to an array of WSAPROTOCOL_INFO structs
  37. static LPWSAPROTOCOL_INFO InstalledProtocols = NULL;
  38.  
  39. // number of WSAPROTOCOL_INFO structs in the InstalledProtocols buffer
  40. static int NumProtocols = 0;
  41.  
  42. // static array of sockets, one for each listening socket
  43. static LISTENDATA ListeningSockets[MAX_LISTENING_SOCKETS];
  44.  
  45. // number of meaningful entries in ListeningSockets
  46. static int NumFound = 0;
  47.  
  48.  
  49.  
  50.  
  51. //
  52. // Function Prototypes -- Internal Functions
  53. //
  54.  
  55. DWORD
  56. IOThreadFunc(
  57.     IN LPVOID ParamPtr);
  58.  
  59. BOOL
  60. HandleSocketEvent(
  61.     IN OUT PCONNDATA ConnData);
  62.  
  63. BOOL
  64. HandleOutputEvent(
  65.     IN OUT PCONNDATA);
  66.  
  67. BOOL
  68. HandleOtherEvent(
  69.     IN     DWORD     WaitStatus,
  70.     IN OUT PCONNDATA ConnData);
  71.  
  72. int
  73. HandleEvents(
  74.     IN PCONNDATA          ConnData,
  75.     IN LPWSANETWORKEVENTS NetworkEvents);
  76.  
  77. BOOL
  78. FillLocalAddress(
  79.     IN LPVOID          SockAddr);
  80.  
  81. int
  82. DoRecv(
  83.     IN PCONNDATA ConnData);
  84.  
  85. int
  86. DoOverlappedCallbackSend(
  87.     IN POUTPUT_REQUEST OutReq,
  88.     IN PCONNDATA       ConnData);
  89.  
  90. int
  91. DoOverlappedEventSend(
  92.     IN POUTPUT_REQUEST OutReq,
  93.     IN PCONNDATA       ConnData);
  94.  
  95. int
  96. DoSend(
  97.     IN POUTPUT_REQUEST OutReq,
  98.     IN PCONNDATA       ConnData);
  99.  
  100. void CALLBACK
  101. SendCompFunc(
  102.     IN DWORD           Error,
  103.     IN DWORD           BytesTransferred,
  104.     IN LPWSAOVERLAPPED OverlappedPtr,
  105.     IN DWORD           Flags);
  106.  
  107. int CALLBACK
  108. AcceptCondFunc(
  109.     IN LPWSABUF    CallerId,
  110.     IN LPWSABUF    CallerData,
  111.     IN LPQOS       CallerSQos,
  112.     IN LPQOS       CallerGQos,
  113.     IN LPWSABUF    CalleeId,
  114.     OUT LPWSABUF   CalleeData,
  115.     OUT GROUP FAR  *Group,
  116.     IN DWORD   CallbackData);
  117.  
  118. LPWSAPROTOCOL_INFO
  119. GetProtoFromSocket(
  120.     IN SOCKET Socket);
  121.  
  122. BOOL
  123. GetMaxMsgSize(
  124.     IN OUT PCONNDATA ConnData);
  125.  
  126.  
  127.  
  128.  
  129. //
  130. // Function Definitions
  131. //
  132.  
  133.  
  134. BOOL
  135. InitWS2(void)
  136. /*++
  137.  
  138. Routine Description:
  139.  
  140.     Calls WSAStartup, makes sure we have a good version of WinSock2
  141.  
  142. Arguments:
  143.  
  144.     None.
  145.  
  146. Return Value:
  147.  
  148.     TRUE - WinSock 2 DLL successfully started up
  149.  
  150.     FALSE - Error starting up WinSock 2 DLL.
  151.  
  152. --*/
  153.  
  154. {
  155.     int           Error;              // catches return value of WSAStartup
  156.     WORD          VersionRequested;   // passed to WSAStartup
  157.     WSADATA       WsaData;            // receives data from WSAStartup
  158.     BOOL          ReturnValue = TRUE; // return value
  159.  
  160.     // Start WinSock 2.  If it fails, we don't need to call
  161.     // WSACleanup().
  162.     VersionRequested = MAKEWORD(VERSION_MAJOR, VERSION_MINOR);
  163.     Error = WSAStartup(VersionRequested, &WsaData);
  164.     if (Error) {
  165.         MessageBox(GlobalFrameWindow,
  166.                    "Could not find high enough version of WinSock",
  167.                    "Error", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  168.         ReturnValue = FALSE;
  169.     } else {
  170.  
  171.         // Now confirm that the WinSock 2 DLL supports the exact version
  172.         // we want. If not, make sure to call WSACleanup().
  173.         if (LOBYTE(WsaData.wVersion) != VERSION_MAJOR ||
  174.             HIBYTE(WsaData.wVersion) != VERSION_MINOR) {
  175.             MessageBox(GlobalFrameWindow,
  176.                        "Could not find the correct version of WinSock",
  177.                        "Error",  MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  178.             WSACleanup();
  179.             ReturnValue = FALSE;
  180.         }
  181.     }
  182.     return(ReturnValue);
  183.  
  184. } // InitWS2()
  185.  
  186.  
  187.  
  188.  
  189.  
  190. BOOL
  191. FindProtocols(void)
  192. /*++
  193.  
  194. Routine Description:
  195.  
  196.     Finds out about all transport protocols installed on the local
  197.     machine and saves the information into global variables.
  198.  
  199. Implementation:
  200.  
  201.     This function uses WSAEnumProtocols to find out about all
  202.     installed protocols on the local machine.  It stores this
  203.     information in two variables which are global to this file;
  204.     InstalledProtocols is a pointer to a buffer of WSAPROTOCOL_INFO
  205.     structs, while NumProtocols is the number of protocols in that
  206.     buffer.  This function is the only function in the file allowed to
  207.     touch these variables.
  208.  
  209. Arguments:
  210.  
  211.     None.
  212.  
  213. Return Value:
  214.  
  215.     TRUE - Successfully initialized the protocol buffer.
  216.  
  217.     FALSE - Some kind of problem arose.  The user is informed of the
  218.     error.
  219.  
  220. --*/
  221. {
  222.  
  223.     DWORD BufferSize = 0;       // size of InstalledProtocols buffer
  224.     char  MsgText[MSG_LEN];     // holds message strings
  225.  
  226.  
  227.     // Call WSAEnumProtocols to figure out how big of a buffer we need.
  228.     NumProtocols = WSAEnumProtocols(NULL,
  229.                                     NULL,
  230.                                     &BufferSize);
  231.  
  232.     if ((NumProtocols != SOCKET_ERROR) && (WSAGetLastError() != WSAENOBUFS)) {
  233.         // We're in trouble!!
  234.         MessageBox(GlobalFrameWindow, "WSAEnumProtocols is broken.", "Error",
  235.                    MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  236.         goto Fail;
  237.     }
  238.  
  239.     // Allocate a buffer, call WSAEnumProtocols to get an array of
  240.     // WSAPROTOCOL_INFO structs.
  241.     InstalledProtocols = (LPWSAPROTOCOL_INFO)malloc(BufferSize);
  242.     if (InstalledProtocols == NULL) {
  243.         MessageBox(GlobalFrameWindow, "malloc failed.", "Error",
  244.                    MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  245.         goto Fail;
  246.     }
  247.     NumProtocols = WSAEnumProtocols(NULL,
  248.                                     (LPVOID)InstalledProtocols,
  249.                                     &BufferSize);
  250.     if (NumProtocols == SOCKET_ERROR) {
  251.         // uh-oh
  252.         wsprintf(MsgText, "WSAEnumProtocols failed.  Error Code: %d",
  253.                  WSAGetLastError());
  254.         MessageBox(GlobalFrameWindow, MsgText, "Error",
  255.                    MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  256.         goto Fail;
  257.     }
  258.     return(TRUE);
  259.  
  260.  Fail:
  261.  
  262.     WSACleanup();
  263.     return(FALSE);
  264.  
  265. } // FindProtocols()
  266.  
  267.  
  268.  
  269.  
  270.  
  271. BOOL
  272. FillLocalAddress(
  273.     IN struct sockaddr *pSockAddr)
  274. /*++
  275.  
  276. Routine Description:
  277.  
  278.     Fills in the struct sockaddr with a local address appropriate for
  279.     the address family, for use in a call to bind.
  280.  
  281. Arguments:
  282.  
  283.     SockAddr -- A pointer to a struct sockaddr which will be filled in
  284.     appropriately, as determined by the particular address family.
  285.     The address family field (sa_family) must already be filled into
  286.     the structure before being passed into this function.
  287.  
  288. Return Value:
  289.  
  290.     TRUE -- FillLocalAddress recognized the address family and
  291.     successfully filled in the struct sockaddr.  This structure is
  292.     ready to be passed to a bind() call.
  293.  
  294.     FALSE -- FillLocalAddress didn't recognize the address family and
  295.     didn't touch the struct sockaddr.
  296.  
  297. --*/
  298. {
  299.  
  300.     struct sockaddr_in *pInetSockAddr; // used to cast SockAddr to an INET address
  301.     struct sockaddr_atm *pATMSockAddr; // used to cast SockAddr to an ATM address
  302.     BOOL ReturnValue = TRUE;          // holds the return value
  303.  
  304.     switch (pSockAddr->sa_family) {
  305.  
  306.         case AF_INET:
  307.  
  308.             // Cast the pointer so we can now access it's fields as a
  309.             // struct sockaddr_in, the address structure for internet
  310.             // addresses.
  311.             pInetSockAddr = (struct sockaddr_in *)pSockAddr;
  312.             if (!DialogBoxParam(GlobalInstance,
  313.                                 "InetListenPortDlg",
  314.                                 GlobalFrameWindow,
  315.                                 InetListenPortDlgProc,
  316.                                 (LPARAM)pInetSockAddr)) {
  317.                 ReturnValue = FALSE;
  318.             }
  319.             break;
  320.  
  321.         case AF_ATM:
  322.             pATMSockAddr = (struct sockaddr_atm *)pSockAddr;
  323.  
  324.             pATMSockAddr->satm_number.AddressType  = SAP_FIELD_ANY;
  325.             pATMSockAddr->satm_blli.Layer2Protocol = SAP_FIELD_ANY;
  326.             pATMSockAddr->satm_blli.Layer3Protocol = SAP_FIELD_ANY;
  327.             pATMSockAddr->satm_bhli.HighLayerInfoType = BHLI_UserSpecific;
  328.  
  329.             ReturnValue = DialogBoxParam(GlobalInstance,
  330.                                          "ATMSOCKADDRDLG",
  331.                                          GlobalFrameWindow,
  332.                                          (DLGPROC)ATMSockAddrProc,
  333.                                          (LPARAM)pATMSockAddr);
  334.             break;
  335.  
  336.         default:
  337.  
  338.             ReturnValue = FALSE;
  339.             break;
  340.     }
  341.     return(ReturnValue);
  342.  
  343. } // FillLocalAddress()
  344.  
  345.  
  346.  
  347.  
  348.  
  349. BOOL
  350. ListenAll(void)
  351.  
  352. /*++
  353.  
  354. Routine Description:
  355.  
  356.     For each installed, connection-oriented protocol, this function
  357.     creates a socket, binds to a local address, and listens on the
  358.     created socket.  The socket is set up for Windows message
  359.     notification for any connection attempts.
  360.  
  361. Arguments:
  362.  
  363.     None.
  364.  
  365. Return Value:
  366.  
  367.     TRUE - Successfully listened on all installed protocols.
  368.  
  369.     FALSE - Error listening on all installed protocols.  It is not an
  370.     error if there are more connection-oriented protocols than
  371.     MAX_LISTENING_SOCKETS installed; in this case we just ignore any
  372.     extra protocols.
  373.  
  374. --*/
  375.  
  376. {
  377.     struct sockaddr *SockAddr;        // holds socket addresses
  378.     int             SockAddrLen;      // length, in bytes, of SockAddrLen
  379.     LPWSAPROTOCOL_INFO COProtocolInfo;   // current protocol info to examine
  380.     int             i;                // counting variable
  381.     char            MsgText[MSG_LEN]; // holds message strings
  382.     int             Error;            // holds return values
  383.     int             Index;            // indexes into text messages
  384.  
  385.  
  386.     // Find all protocols that support connection-oriented data
  387.     // transfer; create a socket, bind to a local address and listen
  388.     // for connections on that socket for each such protocol found.
  389.     // Also fill in an entry in the ListeningSockets array.
  390.     for (i = 0; i < NumProtocols; i++) {
  391.  
  392.         COProtocolInfo = &InstalledProtocols[i];
  393.         assert(COProtocolInfo != NULL);
  394.         if (UseProtocol(COProtocolInfo)) {
  395.  
  396.             // We've found a suitable protocol.  Create a socket, fill
  397.             // in the next entry in ListeningSockets
  398.             ListeningSockets[NumFound].Socket = WSASocket(FROM_PROTOCOL_INFO,
  399.                                                           FROM_PROTOCOL_INFO,
  400.                                                           FROM_PROTOCOL_INFO,
  401.                                                           COProtocolInfo,
  402.                                                           0,
  403.                                                           WSA_FLAG_OVERLAPPED);
  404.             if (ListeningSockets[NumFound].Socket == INVALID_SOCKET) {
  405.                 UCHAR textBuf[MAX_ERROR_TEXT];
  406.                 sprintf(textBuf, "Could not open a socket. [%x]", WSAGetLastError());
  407.                 MessageBox(GlobalFrameWindow, textBuf,
  408.                            "Non-fatal error.",
  409.                            MB_OK | MB_SETFOREGROUND);
  410.                 continue;
  411.             }
  412.             ListeningSockets[NumFound].ProtocolInfo = COProtocolInfo;
  413.  
  414.             // Allocate a block of memory for the socket address and
  415.             // zero it out.
  416.             SockAddrLen = COProtocolInfo->iMaxSockAddr;
  417.             SockAddr = (struct sockaddr *)malloc(SockAddrLen);
  418.  
  419.             if (!SockAddr) {
  420.                 ChatSysError("malloc()",
  421.                              "ListenAll()",
  422.                              TRUE);
  423.             }
  424.             memset((char *)SockAddr, 0, SockAddrLen);
  425.  
  426.             // Get a local address to bind the socket to
  427.             SockAddr->sa_family = (u_short)COProtocolInfo->iAddressFamily;
  428.             FillLocalAddress(SockAddr);
  429.  
  430.             // Bind the socket to SockAddr.
  431.             Error = bind(ListeningSockets[NumFound].Socket,
  432.                          SockAddr,
  433.                          SockAddrLen);
  434.             if (Error == SOCKET_ERROR) {
  435.                 // bind() failed
  436.                 UCHAR textBuf[MAX_ERROR_TEXT];
  437.                 sprintf(textBuf, "Could not bind the socket. [%x]", WSAGetLastError());
  438.                 MessageBox(GlobalFrameWindow, textBuf,
  439.                            "Non-fatal error", MB_OK | MB_SETFOREGROUND);
  440.                 free(SockAddr);
  441.                 continue;
  442.             }
  443.  
  444.             free(SockAddr);
  445.  
  446.             // Set up the socket for windows message event notification.
  447.             // Note that this call automatically puts the socket into
  448.             // non-blocking mode, as if we had called WSAIoctl with
  449.             // the FIONBIO flag.
  450.             Error = WSAAsyncSelect(ListeningSockets[NumFound].Socket,
  451.                                    GlobalFrameWindow,
  452.                                    USMSG_ACCEPT,
  453.                                    FD_ACCEPT);
  454.             if (Error == SOCKET_ERROR) {
  455.                 MessageBox(GlobalFrameWindow, "Error: WSAAsyncSelect()",
  456.                            "Non-fatal error", MB_OK | MB_SETFOREGROUND);
  457.                 continue;
  458.             }
  459.  
  460.             // Listen for incoming connection requests on the socket.
  461.             Error = listen(ListeningSockets[NumFound].Socket,
  462.                            SOMAXCONN);
  463.             if (Error == SOCKET_ERROR) {
  464.                 MessageBox(GlobalFrameWindow, "Error: listen()",
  465.                            "Non-fatal error",
  466.                            MB_OK | MB_SETFOREGROUND);
  467.                 continue;
  468.             }
  469.  
  470.             // Looks good -- increase the count, check for overflow of
  471.             // the max amount, re-iterate if we're ok.
  472.             if (++NumFound == MAX_LISTENING_SOCKETS) {
  473.                 wsprintf(MsgText,
  474.                          "More than %d useable protocols. Ignoring extras.",
  475.                          MAX_LISTENING_SOCKETS);
  476.                 MessageBox(GlobalFrameWindow, MsgText, "Alert",
  477.                            MB_OK | MB_SETFOREGROUND);
  478.                 break;
  479.             }
  480.  
  481.         } // if (UseProtocol(COProtocolInfo))
  482.     } // for(; ; ;)
  483.  
  484.     if (NumFound == 0) {
  485.  
  486.         Index = wsprintf(MsgText,
  487.                          "Couldn't find a suitable protocol ");
  488.         Index += wsprintf(MsgText + Index,
  489.                           "and/or no listening sockets could be opened.\r\n");
  490.         wsprintf(MsgText + Index, "Shall we continue anyway?");
  491.  
  492.         if (MessageBox(GlobalFrameWindow, MsgText, "No protocols.",
  493.                        MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND)
  494.             == IDNO) {
  495.  
  496.             WSACleanup();
  497.             return(FALSE);
  498.         }
  499.     }
  500.  
  501.     return(TRUE);
  502.  
  503. } // ListenAll()
  504.  
  505.  
  506.  
  507.  
  508.  
  509. BOOL
  510. UseProtocol(
  511.     IN LPWSAPROTOCOL_INFO Proto)
  512. /*++
  513.  
  514. Routine Description:
  515.  
  516.     Returns true if Proto is suitable for use by Chat.
  517.  
  518. Arguments:
  519.  
  520.     Proto -- Points to a protocol information struct.
  521.  
  522. Return Value:
  523.  
  524.     TRUE -- Chat likes it.
  525.  
  526.     FALSE -- Get this chintzy protocol out of here!
  527.  
  528. --*/
  529. {
  530.  
  531.     if (!(Proto->dwServiceFlags1 & XP1_CONNECTIONLESS) &&
  532.         //(Proto->dwServiceFlags1 & XP1_GUARANTEED_DELIVERY) &&
  533.         (Proto->dwServiceFlags1 & XP1_GUARANTEED_ORDER)) {
  534.  
  535.         return(TRUE);
  536.  
  537.     } else {
  538.  
  539.         return(FALSE);
  540.     }
  541. } // UseProtocol
  542.  
  543.  
  544.  
  545.  
  546.  
  547. void
  548. CleanUpSockets(void)
  549. /*++
  550.  
  551. Routine Description:
  552.  
  553.     This function closes all listening sockets.
  554.  
  555. Arguments:
  556.  
  557.     None.
  558.  
  559. Return Value:
  560.  
  561.     None.
  562.  
  563. --*/
  564. {
  565.  
  566.     int i; // counting variable
  567.  
  568.     for (i = 0; i < NumFound; i++) {
  569.         closesocket(ListeningSockets[i].Socket);
  570.     }
  571. } // CleanUpSockets()
  572.  
  573.  
  574.  
  575.  
  576.  
  577. int CALLBACK
  578. AcceptCondFunc(
  579.     IN LPWSABUF   CallerId,
  580.     IN LPWSABUF   CallerData,
  581.     IN LPQOS      CallerSQos,
  582.     IN LPQOS      CallerGQos,
  583.     IN LPWSABUF   CalleeId,
  584.     OUT LPWSABUF  CalleeData,
  585.     OUT GROUP FAR *Group,
  586.     IN DWORD  CallbackData)
  587. /*++
  588.  
  589. Routine Description:
  590.  
  591.     Condition function called when an incoming connection request is
  592.     handled.
  593.  
  594. Implementation:
  595.  
  596.     This function allows the user to accept or reject an incoming
  597.     connection request after examining the caller's name and the
  598.     subject of the call. If the call is accepted, and
  599.     connection-time data transfer is supported by the particular
  600.     protocol on which the connection is made, a dialog box comes up
  601.     which prompts the user for his/her name.
  602.  
  603. Arguments:
  604.  
  605.     CallerId -- Supplies the address of the caller.
  606.  
  607.     CallerData -- Supplies the caller's user data.  Chat uses this
  608.     parameter to send the caller's name and the subject of the call.
  609.  
  610.     CallerSQos -- Supplies the forward and backward QOS.
  611.  
  612.     CallerGQos -- Supplies the forward and backward flow specs for the
  613.     socket group the caller is to create.  Not used by chat.
  614.  
  615.     CalleeId -- Supplies the local address.
  616.  
  617.     CalleeData -- Returns user data back to the caller (Chat uses this
  618.     parameter to return the callee's name)
  619.  
  620.     Group -- Returns the appropriate group action to take on the
  621.     connecting socket.  Not used by chat.  Always returns NULL.
  622.  
  623.     CallbackData -- Supplies a pointer the CONNDATA structure
  624.     associated with this connection.
  625.  
  626. Return Value:
  627.  
  628.     CF_ACCEPT - Accept the connection request from the caller.
  629.  
  630.     CF_REJECT - Reject the connection request from the caller.
  631.  
  632. --*/
  633.  
  634. {
  635.     char          MsgText[MSG_LEN];         // build message string here
  636.     char          TitleText[TITLE_LEN + 1]; // build title string here
  637.     PCONNDATA     ConnData;                 // connection-specific data
  638.     int           Index;                    // index into MsgText
  639.     int           ReturnValue = CF_ACCEPT;  // return value
  640.  
  641.     ConnData = (PCONNDATA)CallbackData;
  642.  
  643.     // CallerId contains the socket address of the connecting entity.
  644.     // Copy this into the connection-specific data.
  645.     ConnData->RemoteSockAddr.len = CallerId->len;
  646.     ConnData->RemoteSockAddr.buf = malloc(ConnData->RemoteSockAddr.len);
  647.     if (ConnData->RemoteSockAddr.buf == NULL) {
  648.         ChatSysError("malloc()",
  649.                      "AcceptCondFunc()",
  650.                      TRUE);
  651.     }
  652.     memcpy((char *)ConnData->RemoteSockAddr.buf, (char *)CallerId->buf,
  653.            CallerId->len);
  654.  
  655.     // Translate the RemoteSockAddr into a human readable form, and
  656.     // store it in ConnData->PeerAddress
  657.     GetAddressString(ConnData->PeerAddress,
  658.                      ConnData->RemoteSockAddr.buf,
  659.                      ConnData->RemoteSockAddr.len,
  660.                      ConnData->ProtocolInfo);
  661.  
  662.     Index = wsprintf(MsgText, "Someone is attempting a chat connection.\r\n");
  663.  
  664.     if (CallerData != NULL) {
  665.  
  666.         // The connection request has come with some caller data.  Use
  667.         // it to inform the user of who is trying to connect
  668.         ExtractTwoStrings(CallerData->buf,
  669.                           ConnData->PeerName,
  670.                           NAME_LEN + 1,
  671.                           ConnData->Subject,
  672.                           SUB_LEN + 1);
  673.  
  674.         // Build the strings for the message box and the title of the
  675.         // connection window
  676.         Index += wsprintf(MsgText + Index,
  677.                  "From: %s\r\nSubject: %s\r\n", ConnData->PeerName,
  678.                           ConnData->Subject);
  679.         wsprintf(TitleText, "Connected to: %s @ %s", ConnData->PeerName,
  680.                  ConnData->PeerAddress);
  681.  
  682.     } else {
  683.  
  684.         // There is no caller data...build a string for the title.
  685.         wsprintf(TitleText, "Connected to: %s", ConnData->PeerAddress);
  686.     }
  687.  
  688.     // Continue building MsgText.
  689.     Index += wsprintf(MsgText + Index, "Address: %s\r\n",
  690.                       ConnData->PeerAddress);
  691.     Index += wsprintf(MsgText + Index, "Would you like to accept it?");
  692.  
  693.     // Prompt the user to accept or reject the connection.
  694.     //
  695.     // ****NOTE****
  696.     // This is NOT the right way to do this.  The application should
  697.     // not hold up this thread by putting up this message box, or the
  698.     // dialog box below.  As mentioned in the API spec, this function
  699.     // should  return "as soon as possible", and clearly this is not
  700.     // what's being done here.  Please look to future versions of chat
  701.     // for a fix.  Thanks.
  702.     if (MessageBox(ConnData->ConnectionWindow, MsgText,
  703.                    "Connection Request",
  704.                    MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES) {
  705.  
  706.         // The user has accepted the connection request.
  707.         SetWindowText(ConnData->ConnectionWindow, TitleText);
  708.         if (CalleeData != NULL) {
  709.  
  710.             // We can try to pass user data back. Call up a dialog box
  711.             // to get a name string and put it into CalleeData.
  712.             if (!DialogBoxParam(GlobalInstance,
  713.                                 "AcceptConnectionDlg",
  714.                                 ConnData->ConnectionWindow,
  715.                                 AcceptConnectionDlgProc,
  716.                                 (LPARAM)CalleeData)) {
  717.  
  718.                 CalleeData->len = 0;
  719.             }
  720.         }
  721.         ReturnValue = CF_ACCEPT;
  722.  
  723.     } // if (MessageBox(...))
  724.     else {
  725.  
  726.         // The user has rejected the connection request.
  727.         ReturnValue = CF_REJECT;
  728.     }
  729.     return(ReturnValue);
  730.  
  731. } // AcceptCondFunc()
  732.  
  733.  
  734.  
  735.  
  736.  
  737. BOOL
  738. GetAddressString(
  739.     OUT char            *String,
  740.     IN  LPVOID          SockAddr,
  741.     IN  int             SockAddrLen,
  742.     IN  LPWSAPROTOCOL_INFO ProtocolInfo)
  743. /*++
  744.  
  745. Routine Description:
  746.  
  747.     This function translates the SockAddr into a human-readable
  748.     string, if possible.  If chat doesn't recognize the protocol, then
  749.     the string "(unknown)" is returned in String.
  750.  
  751. Arguments:
  752.  
  753.     String -- Returns the string representing the SockAddr in a
  754.     human-readable form.
  755.  
  756.     SockAddr -- An address.
  757.  
  758.     SockAddrLen -- The length, in bytes, of SockAddr.
  759.  
  760.     ProtocolInfo -- Pointer to the protocol information structure.
  761.  
  762. Return Value:
  763.  
  764.     TRUE -- Chat recognized the protocol family and successfully
  765.     translated the address.
  766.  
  767.     FALSE -- Chat did not recognize the protocol family and returned
  768.     the string "(unknown)".
  769.  
  770. --*/
  771. {
  772.  
  773.     char               *TempString;   // string returned by inet_ntoa
  774.     struct sockaddr_in *SockAddrInet; // casts the address to a sockaddr_in
  775.     BOOL               ReturnValue;   // holds the return value
  776.  
  777.     ReturnValue = TRUE;
  778.  
  779.     switch (ProtocolInfo->iAddressFamily) {
  780.  
  781.         case AF_INET:
  782.  
  783.             // It's an Internet-style address.
  784.             SockAddrInet = (struct sockaddr_in *)SockAddr;
  785.             TempString = inet_ntoa(SockAddrInet->sin_addr);
  786.             if (TempString == NULL) {
  787.                 MessageBox(NULL, "inet_ntoa() failed.", "Error.",
  788.                            MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  789.             } else {
  790.                 strcpy(String, TempString);
  791.             }
  792.             ReturnValue = TRUE;
  793.             break;
  794.  
  795.         default:
  796.  
  797.             strcpy(String, "(unknown)");
  798.             ReturnValue = FALSE;
  799.             break;
  800.     }
  801.     return(ReturnValue);
  802.  
  803. } // GetAddressString()
  804.  
  805.  
  806.  
  807.  
  808.  
  809. int
  810. HandleEvents(
  811.     IN PCONNDATA          ConnData,
  812.     IN LPWSANETWORKEVENTS NetworkEvents)
  813.  
  814. /*++
  815.  
  816. Routine Description:
  817.  
  818.     Handles network events that may occur on a connected socket.
  819.     The events handled by this function are FD_CLOSE, FD_READ, and
  820.     FD_WRITE.
  821.  
  822. Arguments:
  823.  
  824.     ConnData - Supplies a pointer to data for the connection on which
  825.     the event happened.
  826.  
  827.     NetworkEvents - Supplies a WSANETWORKEVENT structure, which is a
  828.     record of the network events that have occurred as well as any
  829.     accompanying error-codes.
  830.  
  831. Return Value:
  832.  
  833.     CHAT_OK -- The network event was successfully handled.
  834.  
  835.     CHAT_ERROR -- Some kind of error occurred while handling the
  836.     event, and the connection should be closed.
  837.  
  838.     CHAT_CLOSED -- The connection has been gracefully closed.
  839.  
  840. --*/
  841.  
  842. {
  843.     int Result;                // holds the result of DoRecv
  844.     int ReturnValue = CHAT_OK; // return value
  845.  
  846.     // The following three if statements all execute unless one gets
  847.     // an error or closed socket, in which case we return immediately.
  848.     if (NetworkEvents->lNetworkEvents & FD_READ) {
  849.  
  850.         // An FD_READ event has occurred on the connected socket.
  851.         if (NetworkEvents->iErrorCode[FD_READ_BIT] == WSAENETDOWN) {
  852.  
  853.             // There is an error.
  854.             ReturnValue = CHAT_ERROR;
  855.             goto Done;
  856.  
  857.         } else {
  858.  
  859.             // Read data off the socket...
  860.             Result = DoRecv(ConnData);
  861.             if ((Result == CHAT_ERROR) || (Result == CHAT_CLOSED)) {
  862.                 ReturnValue = Result;
  863.                 goto Done;
  864.             }
  865.         }
  866.     }
  867.  
  868.     if (NetworkEvents->lNetworkEvents & FD_WRITE) {
  869.  
  870.         // An FD_WRITE event has occurred on the connected socket.
  871.         if (NetworkEvents->iErrorCode[FD_WRITE_BIT] == WSAENETDOWN) {
  872.  
  873.             // There is an error.
  874.             ReturnValue = CHAT_ERROR;
  875.             goto Done;
  876.  
  877.         } else {
  878.  
  879.             // Allow chat to send on this socket, and signal the
  880.             // OuputEventObject in case there is pending output that is
  881.             // not completed due to WSAEWOULDBLOCK.
  882.             ConnData->WriteOk = TRUE;
  883.             SetEvent(ConnData->OutputEventObject);
  884.         }
  885.     }
  886.  
  887.     if (NetworkEvents->lNetworkEvents & FD_CLOSE) {
  888.  
  889.         if (NetworkEvents->iErrorCode[FD_CLOSE_BIT] == 0) {
  890.  
  891.             // A graceful shutdown has occurred...
  892.             ReturnValue = CHAT_CLOSED;
  893.             goto Done;
  894.  
  895.         } else {
  896.  
  897.             // This is some other type of abortive close or failure...
  898.             ReturnValue = CHAT_ABORTED;
  899.             goto Done;
  900.         }
  901.  
  902.     }
  903.  
  904.  Done:
  905.     return(ReturnValue);
  906.  
  907. } // HandleEvents()
  908.  
  909.  
  910.  
  911.  
  912.  
  913. DWORD
  914. IOThreadFunc(
  915.     IN LPVOID ParamPtr)
  916.  
  917. /*++
  918.  
  919. Routine Description:
  920.  
  921.     This routine is invoked as a separate thread to handle all input
  922.     and output for a connection.
  923.  
  924. Implementation:
  925.  
  926.     This thread sits in a loop, waiting for one of several things to
  927.     occur.  These can be:
  928.  
  929.         1. The user interface thread has some input ready to be sent,
  930.         and has signaled the ouput event object.
  931.  
  932.         2. WinSock 2 has indicated there is a network event associated
  933.         with the socket.
  934.  
  935.         3. Callback notification.  This can be via an event or via a
  936.         queued callback function, depending on whether or not we've
  937.         compiled with the CALLBACK_NOTIFICATION flag.
  938.  
  939.     The return value from the wait indicates what has
  940.     happened, and a switch statement handles all the possible cases.
  941.     When there is an error or the connection is being closed, the loop
  942.     is broken and the thread will exit and the connection window will
  943.     be closed (and sent a WM_DESTROY message).
  944.  
  945. Arguments:
  946.  
  947.     ParamPtr - Supplies a pointer to a ConnData structure that holds
  948.     data specific to this connection.
  949.  
  950. Return Value:
  951.  
  952.     0 - Always returns 0.  The return value is not needed.
  953.  
  954. --*/
  955. {
  956.     char             MsgText[MSG_LEN]; // holds message strings
  957.     DWORD            WaitStatus;       // holds return value of the wait
  958.     PCONNDATA        ConnData;         // connection-specific data
  959.     BOOL             KeepGoing = TRUE; // keep processing output requests?
  960.     BOOL             Forever = TRUE;   // constant to avoid warning
  961.  
  962.     ConnData =  (PCONNDATA)ParamPtr;
  963.  
  964.     // Initialize the EventArray.  The only two events in it, for now,
  965.     // are the Socket and Ouput events; if this is the event
  966.     // notification version of chat, then there will be an additional
  967.     // event for each overlapped send waiting for a completion
  968.     // notification.
  969.     ConnData->NumEvents = 2;
  970.     ConnData->EventArray[0] = ConnData->SocketEventObject;
  971.     ConnData->EventArray[1] = ConnData->OutputEventObject;
  972.  
  973.     // Initialize the array of output requests, which is indexed in
  974.     // parallel to the above event array.  When an event is signaled,
  975.     // we can figure out which output request and overlapped
  976.     // structures to free by indexing into this array.
  977.     // These first two entries should never be referenced, because
  978.     // their parallel entries in EventArray (see above) are for the
  979.     // permanent Socket and Output event objects.
  980.     ConnData->OutReqArray[0] = ConnData->OutReqArray[1] = NULL;
  981.  
  982.     while (Forever) {
  983.  
  984.         // Wait for an event (or a queued callback function) to wake
  985.         // us up.  This is an alertable wait state (fAlertable == TRUE).
  986.         WaitStatus = WSAWaitForMultipleEvents(ConnData->NumEvents,
  987.                                               ConnData->EventArray,
  988.                                               FALSE,        // fWaitAll
  989.                                               WSA_INFINITE, // dwTimeout
  990.                                               TRUE);        // fAlertable
  991.  
  992.         // Determine why we woke up and act accordingly.  Note that
  993.         // breaking out of the switch causes us to break out of the
  994.         // while loop as well.  When we don't want to break out of the
  995.         // loop, case statements end with the continue statement.
  996.         switch (WaitStatus) {
  997.  
  998.         case WSA_WAIT_FAILED:
  999.  
  1000.             // A fatal error.  Pop up a message box and break out of
  1001.             // the while loop to end the thread.
  1002.  
  1003.             wsprintf(MsgText,
  1004.                      "WSAWaitForMultipleEvents() failed.  Error code: %d",
  1005.                      WSAGetLastError());
  1006.             MessageBox(ConnData->ConnectionWindow, MsgText, "Fatal Error",
  1007.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1008.             break;
  1009.  
  1010.         case WAIT_IO_COMPLETION:
  1011.  
  1012.             // An I/O completion routine has been executed.  Cleanup
  1013.             // has already occurred in SendCompFunc, so there is
  1014.             // nothing left to do.  Just reiterate through the loop.
  1015.  
  1016.             continue;
  1017.  
  1018.         case WSA_WAIT_EVENT_0:
  1019.  
  1020.             // The SocketEventObject has been signaled.  Handle it in
  1021.             // a separate function.  Break out of the thread if
  1022.             // HandleSocketEvent returns FALSE, indicating error.
  1023.             if (HandleSocketEvent(ConnData)) {
  1024.                 continue;
  1025.             } else {
  1026.                 break;
  1027.             }
  1028.  
  1029.         // Please note: WSA_WAIT_EVENT_[1,2,3] are defined in
  1030.         // chatsock.h, not winsock2.h like WSA_WAIT_EVENT_0
  1031.  
  1032.         case WSA_WAIT_EVENT_1:
  1033.  
  1034.             // The OuputEventObject has been signaled.  Handle it in a
  1035.             // separate function, and break out of the thread if it
  1036.             // returns FALSE
  1037.             if (HandleOutputEvent(ConnData)) {
  1038.                 continue;
  1039.             } else {
  1040.                 break;
  1041.             }
  1042.  
  1043.         default:
  1044.  
  1045.             // Some other event has been signaled.  Handle it in a
  1046.             // separate function, and break out of the thread if it
  1047.             // returns FALSE.
  1048.             if (HandleOtherEvent(WaitStatus, ConnData)) {
  1049.                 continue;
  1050.             } else {
  1051.                 break;
  1052.             }
  1053.  
  1054.         } // switch (WaitStatus)
  1055.  
  1056.         // Break out of the while loop.
  1057.         break;
  1058.  
  1059.     } // while (1)
  1060.  
  1061.     // Thread is ending because the connection was closed or an error
  1062.     // occurred
  1063.     PostMessage(ConnData->ConnectionWindow,
  1064.                 WM_CLOSE,
  1065.                 0,
  1066.                 0);
  1067.     return(0);
  1068.  
  1069. } // IOThreadFunc()
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075. BOOL
  1076. HandleSocketEvent(
  1077.     IN OUT PCONNDATA ConnData)
  1078. /*++
  1079.  
  1080. Routine Description:
  1081.  
  1082.     Handles the case in IOThreadFunc where the thread is woken up by a
  1083.     signal to the socket event object.
  1084.  
  1085. Arguments:
  1086.  
  1087.     ConnData - Supplies a pointer to data for the connection on which
  1088.     the event happened.
  1089.  
  1090. Return Value:
  1091.  
  1092.     TRUE -- Chat successfully handled the event and the thread should
  1093.     continue on.
  1094.  
  1095.     FALSE -- An error occurred and Chat should kill the thread and the
  1096.     connection.
  1097.  
  1098. --*/
  1099. {
  1100.     int              Result;           // holds return values
  1101.     WSANETWORKEVENTS NetworkEvents;    // tells us what events happened
  1102.     char             MsgText[MSG_LEN]; // holds text strings
  1103.     BOOL             ReturnValue;      // holds the return value
  1104.  
  1105.     // Find out what happened and act accordingly.
  1106.     Result = WSAEnumNetworkEvents(ConnData->Socket,
  1107.                                   ConnData->SocketEventObject,
  1108.                                   &NetworkEvents);
  1109.     if (Result == SOCKET_ERROR) {
  1110.  
  1111.         // Handle the fatal error.
  1112.         wsprintf(MsgText,
  1113.                  "WSAEnumNetworkEvents failed.  Error code: %d",
  1114.                  Result);
  1115.         MessageBox(GlobalFrameWindow, MsgText, "Fatal Error",
  1116.                    MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1117.         ReturnValue = FALSE;
  1118.  
  1119.     } else {
  1120.  
  1121.         // Handle all of the network events on the given socket
  1122.         Result = HandleEvents(ConnData, &NetworkEvents);
  1123.  
  1124.         if (Result == CHAT_CLOSED) {
  1125.  
  1126.             // HandleEvents() has determined that the remote party
  1127.             // has terminated the connection.  Inform the user, and
  1128.             // return.
  1129.             if (ConnData->PeerName[0] != 0) {
  1130.                 wsprintf(MsgText,
  1131.                          "%s @ %s has terminated the connection.",
  1132.                          ConnData->PeerName, ConnData->PeerAddress);
  1133.             } else {
  1134.                 wsprintf(MsgText,
  1135.                          "The party at %s has terminated the connection.",
  1136.                          ConnData->PeerAddress);
  1137.             }
  1138.             MessageBox(ConnData->ConnectionWindow, MsgText, "Sorry!",
  1139.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1140.             ReturnValue = FALSE;
  1141.  
  1142.         } else if (Result == CHAT_ABORTED) {
  1143.  
  1144.             // HandleEvents has determined that the connection has
  1145.             // been aborted due to an undetermined error.
  1146.             MessageBox(ConnData->ConnectionWindow,
  1147.                        "The connection has been broken.",
  1148.                        "Connection aborted.",
  1149.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1150.             ReturnValue = FALSE;
  1151.  
  1152.         } else if (Result == CHAT_ERROR) {
  1153.  
  1154.             // HandleEvents() has returned an error.  Inform the
  1155.             // user and break to exit the thread and kill the window.
  1156.             MessageBox(ConnData->ConnectionWindow,
  1157.                        "An unidentified network or system error occurred.",
  1158.                        "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1159.             ReturnValue = FALSE;
  1160.  
  1161.         } else if (Result == CHAT_OK) {
  1162.  
  1163.             // Inform the caller that everything went fine.
  1164.             ReturnValue = TRUE;
  1165.  
  1166.  
  1167.         } else {
  1168.  
  1169.             // This case should only occur if there is a
  1170.             // programming error.  Break out of the while loop to
  1171.             // kill the thread, the window, and therefore the
  1172.             // connection.
  1173.             MessageBox(ConnData->ConnectionWindow,
  1174.                        "HandleEvents() returned an unexpected value.",
  1175.                        "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1176.             ReturnValue = FALSE;
  1177.         }
  1178.     }
  1179.  
  1180.     return(ReturnValue);
  1181.  
  1182. } // HandleSocketEvent()
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188. BOOL
  1189. HandleOutputEvent(
  1190.     IN OUT PCONNDATA ConnData)
  1191. /*++
  1192.  
  1193. Routine Description:
  1194.  
  1195.     Handles the case in IOThreadFunc where the thread is woken up by a
  1196.     signal to the output event object.
  1197.  
  1198. Arguments:
  1199.  
  1200.     ConnData - Supplies a pointer to data for the connection on which
  1201.     the event happened.
  1202.  
  1203. Return Value:
  1204.  
  1205.     TRUE -- Chat successfully handled the event and the thread should
  1206.     continue on.
  1207.  
  1208.     FALSE -- An error occurred and Chat should kill the thread and the
  1209.     connection.
  1210.  
  1211. --*/
  1212. {
  1213.     BOOL            ReturnValue; // holds the return value
  1214.     BOOL            KeepGoing;   // keep pulling requests off the queue?
  1215.     POUTPUT_REQUEST OutReq;      // pointer to the output request
  1216.     int             Result;      // holds results of functions
  1217.  
  1218.     ReturnValue = TRUE;
  1219.  
  1220.     // First we check to see if a previous send attempt failed with
  1221.     // WSAEWOULDBLOCK; if so, we don't have to bother trying to send
  1222.     // data until we get an FD_WRITE network event, so just return
  1223.     // with TRUE to indicate that the thread should wait again.
  1224.     if (ConnData->WriteOk) {
  1225.  
  1226.         // This loop pulls output requests off the queue and hands
  1227.         // them to DoSend.
  1228.         KeepGoing = TRUE;
  1229.         while (KeepGoing) {
  1230.  
  1231.             OutReq = (POUTPUT_REQUEST)QRemove(ConnData->OutputQueue);
  1232.             if (OutReq == NULL) {
  1233.  
  1234.                 // Nothing is left on the queue.
  1235.                 KeepGoing = FALSE;
  1236.                 ReturnValue = TRUE;
  1237.  
  1238.             } else {
  1239.  
  1240.                 // Do the output
  1241.                 Result = DoSend(OutReq, ConnData);
  1242.                 if (Result == CHAT_WOULD_BLOCK) {
  1243.  
  1244.                     // The send would have blocked; we need to
  1245.                     // requeue the output request and wait for an
  1246.                     // FD_WRITE network event.
  1247.                     KeepGoing = FALSE;
  1248.                     QInsertAtHead(ConnData->OutputQueue, (LPVOID)OutReq);
  1249.                     ReturnValue = TRUE;
  1250.  
  1251.                 } else if (Result == CHAT_ERROR) {
  1252.  
  1253.                     // An error occurred in DoSend.  Set KeepGoing to
  1254.                     // FALSE in order to get us out of the loop.
  1255.                     KeepGoing = FALSE;
  1256.                     ReturnValue = FALSE;
  1257.                     MessageBox(ConnData->ConnectionWindow,
  1258.                                "Error sending data.",
  1259.                                "Error.",
  1260.                                MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1261.  
  1262.                 } else {
  1263.  
  1264.                     // DoSend returned CHAT_OK.  Keep looping.
  1265.                     continue;
  1266.                 }
  1267.             }
  1268.         } // while (KeepGoing)
  1269.     } // if (ConnData->WriteOk)
  1270.  
  1271.     return(ReturnValue);
  1272.  
  1273. } // HandleOutputEvent()
  1274.  
  1275.  
  1276.  
  1277.  
  1278.  
  1279. BOOL
  1280. HandleOtherEvent(
  1281.     IN     DWORD     WaitStatus,
  1282.     IN OUT PCONNDATA ConnData)
  1283. /*++
  1284.  
  1285. Routine Description:
  1286.  
  1287.     Handles the case in IOThreadFunc where the thread is woken up by
  1288.     an event that is either an overlapped I/O event or was not
  1289.     specified in the event array (which is an error!).
  1290.  
  1291. Arguments:
  1292.  
  1293.     WaitStatus -- Supplies the value returned by
  1294.     WSAWaitForMultipleEvents.
  1295.  
  1296.     ConnData - Supplies a pointer to data for the connection on which
  1297.     the event happened.
  1298.  
  1299. Return Value:
  1300.  
  1301.     TRUE -- Chat successfully handled the event and the thread should
  1302.     continue on.
  1303.  
  1304.     FALSE -- An error occurred and Chat should kill the thread and the
  1305.     connection.
  1306.  
  1307. --*/
  1308. {
  1309.     POUTPUT_REQUEST OutReq;           // points to an output request
  1310.     BOOL            ReturnValue;      // holds the return value
  1311.     DWORD           Count;            // counting variable
  1312.     char            MsgText[MSG_LEN]; // holds message strings
  1313.  
  1314.     // First do a sanity check to make sure the index returned is
  1315.     // within the bounds of what WE think is the event array.
  1316.     if ((WaitStatus >= WSA_WAIT_EVENT_0) &&
  1317.         (WaitStatus <= (WSA_WAIT_EVENT_0  + ConnData->NumEvents - 1))) {
  1318.  
  1319.         // Free the data buffer, the overlapped structure, the output
  1320.         // request itself, and the event
  1321.         OutReq = ConnData->OutReqArray[WaitStatus - WSA_WAIT_EVENT_0];
  1322.         free(OutReq->Buffer.buf);
  1323.         free(OutReq->Overlapped);
  1324.         free(OutReq);
  1325.  
  1326.         CloseHandle(ConnData->EventArray[WaitStatus - WSA_WAIT_EVENT_0]);
  1327.  
  1328.         // Update all our event and output request arrays to
  1329.         // reflect that the overlapped send has completed.
  1330.         ConnData->NumEvents--;
  1331.         for (Count = (WaitStatus - WSA_WAIT_EVENT_0);
  1332.              Count < ConnData->NumEvents;
  1333.              Count++) {
  1334.             ConnData->EventArray[Count] = ConnData->EventArray[Count + 1];
  1335.             ConnData->OutReqArray[Count] = ConnData->OutReqArray[Count + 1];
  1336.         }
  1337.         ReturnValue = TRUE;
  1338.  
  1339.     } else {
  1340.  
  1341.         // WSAWaitForMultipleEvents returned an unexpected
  1342.         // value...
  1343.         wsprintf(MsgText, "WSAWaitForMultipleEvents() returned %d.",
  1344.                  WaitStatus);
  1345.         MessageBox(GlobalFrameWindow, MsgText, "Error.",
  1346.                    MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1347.         ReturnValue = FALSE;
  1348.     }
  1349.  
  1350.     return(ReturnValue);
  1351.  
  1352. } // HandleOtherEvent()
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358. void
  1359. HandleAcceptMessage(
  1360.     IN HWND   ConnectionWindow,
  1361.     IN SOCKET Socket,
  1362.     IN LPARAM LParam)
  1363. /*++
  1364.  
  1365. Routine Description:
  1366.  
  1367.     Handles the reception of a USMSG_ACCEPT message, which indicates a
  1368.     connection attempt is incoming.
  1369.  
  1370. Implementation:
  1371.  
  1372.     This function lets the user decide whether to accept the
  1373.     connection; if he or she does, the function  initializes
  1374.     connection-specific data, calls WSAEventSelect to register
  1375.     interest in certain network events, and starts a network event
  1376.     handling thread.
  1377.  
  1378. Arguments:
  1379.  
  1380.     ConnectionWindow -- Handle to the connection window associated
  1381.     with this connection request.
  1382.  
  1383.     Socket -- Contains the handle to the listening socket to which the
  1384.     connection request has been made.
  1385.  
  1386.     LParam -- The LParam that was delivered with the USMSG_ACCEPT
  1387.     message; contains the error code.
  1388.  
  1389. Return Value:
  1390.  
  1391.     None.
  1392.  
  1393. --*/
  1394. {
  1395.  
  1396.     int       Error;            // gets error code if necessary
  1397.     char      MsgText[MSG_LEN]; // holds message strings
  1398.     DWORD     ThreadId;         // needed for CreateThread
  1399.     PCONNDATA ConnData;         // connection-specific data
  1400.  
  1401.     ConnData = GetConnData(ConnectionWindow);
  1402.  
  1403.     Error = WSAGETSELECTERROR(LParam);
  1404.  
  1405.     // Check to see if there was an error on the connection attempt.
  1406.     if (Error) {
  1407.  
  1408.         // Some kind of error occurred.
  1409.         if (Error == WSAENETDOWN) {
  1410.             MessageBox(ConnectionWindow,
  1411.                        "The network is down!", "Uh-oh",
  1412.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1413.         } else {
  1414.             MessageBox(ConnectionWindow,
  1415.                        "Unknown error on FD_ACCEPT", "Error",
  1416.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1417.         }
  1418.         goto Fail;
  1419.     }
  1420.  
  1421.     // Get a pointer to the associated protocol information structure
  1422.     // for the socket we are listening on (Socket). This will be the
  1423.     // same as the protocol info for the new socket.  Note that we
  1424.     // could have allocated a new buffer and called getsockopt with
  1425.     // the SO_PROTOCOL_INFO option.  But since we've already allocated
  1426.     // the memory, this way is more efficient.
  1427.     ConnData->ProtocolInfo = GetProtoFromSocket(Socket);
  1428.     assert(ConnData->ProtocolInfo != NULL);
  1429.  
  1430.     // Accept the connection (this calls AcceptCondFunc, of course,
  1431.     // before actually accepting the connection).
  1432.     {
  1433.         struct sockaddr address;
  1434.         int address_len;
  1435.  
  1436.         address_len = sizeof (address);
  1437.         ConnData->Socket = WSAAccept(Socket,
  1438.                                      &address,
  1439.                                      &address_len,
  1440.                                      NULL,
  1441.                                      (DWORD)NULL);
  1442. //         ConnData->Socket = WSAAccept(Socket,
  1443. //                                      NULL,
  1444. //                                      NULL,
  1445. //                                      AcceptCondFunc,
  1446. //                                      (DWORD)ConnData);
  1447.     }
  1448.  
  1449.     if (ConnData->Socket == INVALID_SOCKET) {
  1450.  
  1451.         // WSAAccept failed -- inform the user and that's all.
  1452.         Error = WSAGetLastError();
  1453.         if (Error != WSAECONNREFUSED) {
  1454.  
  1455.             // An unexpected error code.
  1456.             wsprintf(MsgText, "WSAAccept failed.  Error code: %d",
  1457.                      Error);
  1458.             MessageBox(ConnectionWindow, MsgText, "Error",
  1459.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1460.             goto Fail;
  1461.  
  1462.         } else {
  1463.  
  1464.             // AcceptCondFunc returned CF_REJECT...
  1465.             MessageBox(GlobalFrameWindow,
  1466.                        "The connection attempt has been refused.",
  1467.                        "Connection refused.", MB_OK | MB_SETFOREGROUND);
  1468.             goto Fail;
  1469.         }
  1470.     }
  1471.  
  1472.     WSAAsyncSelect(ConnData->Socket,
  1473.                    GlobalFrameWindow,
  1474.                    0,
  1475.                    0);
  1476.  
  1477.     // Put Connection in Event Object Notification Mode.
  1478.     WSAEventSelect(ConnData->Socket,
  1479.                    ConnData->SocketEventObject,
  1480.                    FD_READ | FD_WRITE | FD_CLOSE);
  1481.  
  1482.     // Determine the maximum message size, if any.
  1483.     if (!GetMaxMsgSize(ConnData)) {
  1484.         goto Fail;
  1485.     }
  1486.  
  1487.     // Start the I/O thread, and save the thread handle.
  1488.     ConnData->IOThreadHandle =
  1489.       CreateThread(NULL,
  1490.                    0,
  1491.                    (LPTHREAD_START_ROUTINE)IOThreadFunc,
  1492.                    ConnData,
  1493.                    0,
  1494.                    &ThreadId);
  1495.     if (ConnData->IOThreadHandle == NULL) {
  1496.         ChatSysError("CreateThread()",
  1497.                      "HandleAcceptMessage()",
  1498.                      TRUE);
  1499.     }
  1500.  
  1501.     return;
  1502.  
  1503.  Fail:
  1504.  
  1505.     DestroyWindow(ConnectionWindow);
  1506.     return;
  1507.  
  1508. } // HandleAcceptMessage()
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514. void
  1515. HandleConnectMessage(
  1516.     IN HWND   ConnectionWindow,
  1517.     IN LPARAM LParam)
  1518. /*++
  1519.  
  1520. Routine Description:
  1521.  
  1522.     Handles the reception of a USMSG_CONNECT message, which indicates
  1523.     a connection attempt is complete (though not necessarily
  1524.     successful).
  1525.  
  1526. Implementation:
  1527.  
  1528.     As with HandleAcceptMessages, this function initializes
  1529.     connection-specific data, calls WSAEventSelect to register
  1530.     interest in certain network events, and starts a network event
  1531.     handling thread.
  1532.  
  1533. Arguments:
  1534.  
  1535.     ConnectionWindow -- Handle to the connection window associated
  1536.     with this connection request.
  1537.  
  1538.     LParam -- Contains the LParam that was a parameter of the
  1539.     USMSG_CONNECT message.
  1540.  
  1541. Return Value:
  1542.  
  1543.     None.
  1544.  
  1545. --*/
  1546. {
  1547.  
  1548.     PCONNDATA ConnData;               // connection-specific data
  1549.     char      TitleText[TITLE_LEN];   // text buffer for window title
  1550.     DWORD     ThreadId;               // needed for CreateThread()
  1551.     int       Error;                  // holds error codes
  1552.  
  1553.     Error = WSAGETSELECTERROR(LParam);
  1554.  
  1555.     // Check to see if there was an error on the connection attempt.
  1556.     if (Error) {
  1557.         char textBuf[80];
  1558.         sprintf(textBuf, "Connect error code: %x", Error);
  1559.         MessageBox(NULL, textBuf, NULL, MB_OK);
  1560.  
  1561.         // Some kind of error occurred.
  1562.         if (Error == WSAECONNREFUSED) {
  1563.  
  1564.             MessageBox(ConnectionWindow,
  1565.                        "Your connection attempt has been refused",
  1566.                        "Connection Refused",
  1567.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1568.         } else {
  1569.  
  1570.             MessageBox(ConnectionWindow,
  1571.                        "Couldn't connect",
  1572.                        "Error",
  1573.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  1574.         }
  1575.  
  1576.         goto Fail;
  1577.  
  1578.     }
  1579.  
  1580.     // Connection has been accepted.  Change the title of the
  1581.     // connection window to reflect who the user has connected to
  1582.     ConnData = GetConnData(ConnectionWindow);
  1583.  
  1584.     if (ConnData->CalleeBuffer.len != 0) {
  1585.  
  1586.         // The callee buffer contains the connection-time data
  1587.         // sent by the callee. -- a string containing the name of
  1588.         // the callee.
  1589.         wsprintf(TitleText, "Connected To: %s @ %s",
  1590.                  ConnData->CalleeBuffer.buf, ConnData->PeerAddress);
  1591.     } else {
  1592.  
  1593.         // ConnData->PeerAddress just contains the address that
  1594.         // the user typed in before the connection attempt.
  1595.         wsprintf(TitleText, "Connected To: %s", ConnData->PeerAddress);
  1596.     }
  1597.     SetWindowText(ConnectionWindow, TitleText);
  1598.  
  1599.     WSAAsyncSelect(ConnData->Socket,
  1600.                    GlobalFrameWindow,
  1601.                    0,
  1602.                    0);
  1603.  
  1604.     // Put Connection in Event Object Notification Mode.
  1605.     WSAEventSelect(ConnData->Socket,
  1606.                    ConnData->SocketEventObject,
  1607.                    FD_READ | FD_WRITE | FD_CLOSE);
  1608.  
  1609.     // Determine the maximum message size, if any.
  1610.     if (!GetMaxMsgSize(ConnData)) {
  1611.         goto Fail;
  1612.     }
  1613.  
  1614.     // Start the I/O thread, and save the thread handle.
  1615.     ConnData->IOThreadHandle =
  1616.       CreateThread(NULL,
  1617.                    0,
  1618.                    (LPTHREAD_START_ROUTINE)IOThreadFunc,
  1619.                    ConnData,
  1620.                    0,
  1621.                    &ThreadId);
  1622.     if (ConnData->IOThreadHandle == NULL) {
  1623.         ChatSysError("CreateThread()",
  1624.                      "HandleConnectMessage()",
  1625.                      TRUE);
  1626.     }
  1627.  
  1628.     return;
  1629.  
  1630.  Fail:
  1631.  
  1632.     DestroyWindow(ConnectionWindow);
  1633.     return;
  1634.  
  1635. } // HandleConnectMessage()
  1636.  
  1637.  
  1638.  
  1639.  
  1640.  
  1641. BOOL
  1642. GetMaxMsgSize(
  1643.     IN OUT PCONNDATA ConnData)
  1644. /*++
  1645.  
  1646. Routine Description:
  1647.  
  1648.     Determines the maximum message size (if any) of a connected
  1649.     socket.  The connection must already be established, i.e. the
  1650.     socket must be bound to a local address, for this function to
  1651.     work.  Fills the correct value into a field of the
  1652.     connection-specific data.
  1653.  
  1654. Arguments:
  1655.  
  1656.     ConnData -- Connection data for a connected socket.
  1657.  
  1658. Return Value:
  1659.  
  1660.     TRUE -- The maximum message size was succesfully determined and
  1661.     stored in ConnData->MaxMsgSize.
  1662.  
  1663.     FALSE -- There was an error calling getsockopt to get the maximum
  1664.     message size.
  1665.  
  1666. --*/
  1667. {
  1668.     BOOL ReturnValue = TRUE;       // return value
  1669.     int  DwordLen = sizeof(DWORD); // sizeof a DWORD!
  1670.     int  Error;                    // return value of getsockopt
  1671.  
  1672.     if ((ConnData->ProtocolInfo->dwMessageSize == 0) ||
  1673.         (ConnData->ProtocolInfo->dwMessageSize == 0xffffffff)) {
  1674.  
  1675.         // Either the protocol isn't message-oriented, or there is no
  1676.         // maximum message size.
  1677.         ConnData->MaxMsgSize = NO_MAX_MSG_SIZE;
  1678.  
  1679.     } else {
  1680.  
  1681.         // There is a maximum message size.  Note it.
  1682.         if (ConnData->MaxMsgSize == 0x1) {
  1683.  
  1684.             // The actual maximum message size was not stored in the
  1685.             // protocol information structure -- rather, we need to
  1686.             // get it using getsockopt().
  1687.             Error = getsockopt(ConnData->Socket,
  1688.                                SOL_SOCKET,
  1689.                                SO_MAX_MSG_SIZE,
  1690.                                (char *)&ConnData->MaxMsgSize,
  1691.                                &DwordLen);
  1692.             if (Error) {
  1693.                 ReturnValue = FALSE;
  1694.             }
  1695.  
  1696.         } // if (ConnData->MaxMsgSize == 0x1)
  1697.         else {
  1698.  
  1699.             // The message size is stored in the protocol information
  1700.             // structure.  Use it.
  1701.             ConnData->MaxMsgSize = ConnData->ProtocolInfo->dwMessageSize;
  1702.         }
  1703.  
  1704.  
  1705.     } // else
  1706.  
  1707.     return(ReturnValue);
  1708.  
  1709. } // GetMaxMsgSize()
  1710.  
  1711.  
  1712.  
  1713.  
  1714.  
  1715. BOOL
  1716. IsSendable(
  1717.     char Char)
  1718. /*++
  1719.  
  1720. Routine Description:
  1721.  
  1722.     Determines whether a certain character value is ok to send over
  1723.     the socket to the far end.  Eliminates most non-printable
  1724.     characters except for newline and backspace.
  1725.  
  1726. Arguments:
  1727.  
  1728.     Char -- Supplies the character to be tested.
  1729.  
  1730. Return Value:
  1731.  
  1732.     TRUE -- The character should be sent as is.
  1733.  
  1734.     FALSE -- The character should not be sent.
  1735.  
  1736. --*/
  1737. {
  1738.  
  1739.     if (isprint(Char) || (Char == '\b') ||
  1740.        (Char == '\r') || (Char == '\t') ||
  1741.        (Char == '\n') ){
  1742.         return(TRUE);
  1743.     } else {
  1744.         return(FALSE);
  1745.     }
  1746.  
  1747. } // IsSendable()
  1748.  
  1749.  
  1750.  
  1751.  
  1752.  
  1753. int
  1754. DoRecv(
  1755.     IN PCONNDATA ConnData)
  1756.  
  1757. /*++
  1758.  
  1759. Routine Description:
  1760.  
  1761.     Receives as much available data as possible up to the size of the
  1762.     receive buffer-1 (BUFFER_LENGTH-1).  A single byte is reserved at
  1763.     the end of the receive buffer to append a terminating NULL.
  1764.  
  1765. Arguments:
  1766.  
  1767.     ConnData -- Points to the data for the connection that is ready to
  1768.     receive data.
  1769.  
  1770. Return Value:
  1771.  
  1772.     CHAT_OK -- Received data was successfully sent to the receive edit
  1773.            control.
  1774.  
  1775.     CHAT_ERROR -- Error receiving data.
  1776.  
  1777.     CHAT_CLOSED -- The socket was gracefully closed.
  1778.  
  1779. --*/
  1780.  
  1781. {
  1782.     DWORD  NumBytes;               // stores how many bytes we received
  1783.     int    Error;                  // gets error values
  1784.     int    Result;                 // gets return value from WSARecv
  1785.     char   Buf[BUFFER_LENGTH];     // buffer to receive data
  1786.     int    ReturnValue = CHAT_OK;  // returnValue
  1787.     WSABUF RecvBuffer;             // WSABuf to pass to WSARecv
  1788.     DWORD  Flags;                  // flags for WSARecv
  1789.  
  1790.     RecvBuffer.buf = Buf;
  1791.     RecvBuffer.len = BUFFER_LENGTH - 1;
  1792.  
  1793.     {
  1794.         int socket_type;
  1795.  
  1796.         socket_type = ConnData->ProtocolInfo->iSocketType;
  1797.         if ((socket_type == SOCK_DGRAM) ||
  1798.             (socket_type == SOCK_RDM) ||
  1799.             (socket_type == SOCK_SEQPACKET)) {
  1800.             Flags = MSG_PARTIAL;
  1801.             // Allow  message-oriented  delivery to be received within
  1802.             // our preferred buffer length without losing the trailing
  1803.             // part of longer messages.
  1804.         }
  1805.         else {
  1806.             Flags = 0;
  1807.             // The  MSG_PARTIAL  flag  is  not required and may not be
  1808.             // allowed for stream-oriented protocols.
  1809.         }
  1810.     }
  1811.  
  1812.     // Do the receive
  1813.     Result = WSARecv(ConnData->Socket,
  1814.                      &RecvBuffer,
  1815.                      1,
  1816.                      &NumBytes,
  1817.                      &Flags,
  1818.                      NULL,
  1819.                      NULL);
  1820.  
  1821.     // Check for errors.
  1822.     if (Result == SOCKET_ERROR) {
  1823.  
  1824.         Error = WSAGetLastError();
  1825.  
  1826.         switch (Error) {
  1827.  
  1828.         case WSAENETRESET:  // flow through
  1829.         case WSAECONNRESET:
  1830.  
  1831.             // The remote party has reset the connection.
  1832.             ReturnValue = CHAT_CLOSED;
  1833.             goto Done;
  1834.  
  1835.         case WSAEWOULDBLOCK:
  1836.  
  1837.             // No data received; return to wait for another read event.
  1838.             ReturnValue = CHAT_OK;
  1839.  
  1840.         default:
  1841.  
  1842.             // Some other error...hit the panic button.
  1843.             ReturnValue = CHAT_ERROR;
  1844.             goto Done;
  1845.         }
  1846.  
  1847.     }
  1848.  
  1849.     // Append a NULL to the text buffer.
  1850.     RecvBuffer.buf[NumBytes] = '\0';
  1851.  
  1852.     // Output the received text into the receive edit control.
  1853.     OutputString(ConnData->RecvWindow, RecvBuffer.buf);
  1854.  
  1855.  Done:
  1856.     return(ReturnValue);
  1857.  
  1858. } // DoRecv()
  1859.  
  1860.  
  1861.  
  1862.  
  1863.  
  1864. int
  1865. DoOverlappedCallbackSend(
  1866.     IN POUTPUT_REQUEST OutReq,
  1867.     IN PCONNDATA       ConnData)
  1868.  
  1869. /*++
  1870.  
  1871. Routine Description:
  1872.  
  1873.     Sends a buffer of data over a connected socket using overlapped
  1874.     I/O with callback function completion notification.
  1875.  
  1876. Implementation:
  1877.  
  1878.     This function just does an overlapped send, giving WinSock 2 a
  1879.     completion function which will be called when the operation has
  1880.     finished, and within which cleanup will occur.
  1881.  
  1882. Arguments:
  1883.  
  1884.     OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
  1885.     output request.
  1886.  
  1887.     ConnData -- Supplies a pointer to a CONNDATA structure, which
  1888.     identifies a Chat connection.
  1889.  
  1890. Return Value:
  1891.  
  1892.     CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
  1893.  
  1894.     CHAT_ERROR -- A unexpected error occurred.
  1895.  
  1896.     CHAT_OK -- The send was successfully initiated. WinSock 2 will
  1897.     execute the callback function when the send has completed.
  1898.  
  1899. --*/
  1900.  
  1901. {
  1902.     int             Size = 0;      // how many bytes we send
  1903.     int             Error;         // return value of WSASend
  1904.     int             Errno;         // result of WSAGetLastError
  1905.     LPWSABUF        Buffers;       // points to an array of WSABUFs
  1906.     DWORD           BytesSent;     // needed in WSASend
  1907.     int             ReturnValue;   // the return value
  1908.  
  1909.     ReturnValue = CHAT_OK;
  1910.  
  1911.     // Allocate an OVERLAPPED structure.
  1912.     OutReq->Overlapped = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
  1913.     if (OutReq->Overlapped == NULL) {
  1914.         ChatSysError("malloc()",
  1915.                      "DoOverlappedCallbackSend()",
  1916.                      TRUE);
  1917.     }
  1918.     Buffers = &OutReq->Buffer;
  1919.  
  1920.     // The hEvent field of the Overlapped structure is not used
  1921.     // for callback notification...thus we can use it any way we
  1922.     // want to pass information to the callback routine.  We use
  1923.     // it to store a pointer to the OutReq associated with this
  1924.     // overlapped send operation, so the callback function can
  1925.     // free the memory.
  1926.     OutReq->Overlapped->hEvent = (WSAEVENT)OutReq;
  1927.  
  1928.     Error = WSASend(ConnData->Socket,
  1929.                     Buffers,
  1930.                     1,
  1931.                     &BytesSent,
  1932.                     0,
  1933.                     OutReq->Overlapped,
  1934.                     SendCompFunc);
  1935.  
  1936.     if (Error == SOCKET_ERROR) {
  1937.  
  1938.         // There is an error...
  1939.         Errno = WSAGetLastError();
  1940.         if (Errno == WSAEWOULDBLOCK) {
  1941.  
  1942.             // WSAEWOULDBLOCK means we have to wait for an FD_WRITE
  1943.             // before we can send.
  1944.             ConnData->WriteOk = FALSE;
  1945.             ReturnValue = CHAT_WOULD_BLOCK;
  1946.  
  1947.         } else if (Errno == WSA_IO_PENDING) {
  1948.  
  1949.             // Overlapped send successfully initiated.
  1950.             ReturnValue = CHAT_OK;
  1951.         }
  1952.         else {
  1953.  
  1954.             // An unexpected error occurred.
  1955.             ReturnValue = CHAT_ERROR;
  1956.         }
  1957.  
  1958.     }
  1959.  
  1960.     // No error -- the I/O request was completed immediately...
  1961.     return(ReturnValue);
  1962.  
  1963. } // DoOverlappedCallbackSend()
  1964.  
  1965.  
  1966.  
  1967.  
  1968.  
  1969. int
  1970. DoOverlappedEventSend(
  1971.     IN POUTPUT_REQUEST OutReq,
  1972.     IN PCONNDATA       ConnData)
  1973.  
  1974. /*++
  1975.  
  1976. Routine Description:
  1977.  
  1978.     Sends a buffer of data over a connected socket using overlapped
  1979.     I/O with event notification.
  1980.  
  1981. Implementation:
  1982.  
  1983.     If the overlapped send is succesfully initiated, this function
  1984.     increases the event count and adds an entry to the event array of
  1985.     the associated connection.  During IOThreadFunc, the thread will
  1986.     thus wait on the new event as well, and will perform the
  1987.     appropriate cleanup action when awoken.
  1988.  
  1989. Arguments:
  1990.  
  1991.     OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
  1992.     output request.
  1993.  
  1994.     ConnData -- Supplies a pointer to a CONNDATA structure, which
  1995.     identifies a Chat connection.
  1996.  
  1997. Return Value:
  1998.  
  1999.     CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
  2000.  
  2001.     CHAT_ERROR -- A unexpected error occurred.
  2002.  
  2003.     CHAT_OK -- The send was successfully initiated and the new event
  2004.     placed in the event array; it will be signaled by WinSock 2 when
  2005.     the send operation has completed.
  2006.  
  2007. --*/
  2008.  
  2009. {
  2010.     int             Size = 0;      // how many bytes we send
  2011.     int             Error;         // return value of WSASend
  2012.     int             Errno;         // result of WSAGetLastError
  2013.     LPWSABUF        Buffers;       // points to an array of WSABUFs
  2014.     DWORD           BytesSent;     // needed in WSASend
  2015.     int             ReturnValue;   // the return value
  2016.  
  2017.     ReturnValue = CHAT_OK;
  2018.  
  2019.     // Allocate an OVERLAPPED structure.
  2020.  
  2021.     // Note that the pointer to an overlapped structure is kept in
  2022.     // OutReq.  We use an array of OutReq pointers that is parallel to
  2023.     // the event array.  With that one pointer, then, we can find the
  2024.     // associated Overlapped structure and free it, and then free the
  2025.     // OutReq structure itself.
  2026.     OutReq->Overlapped = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
  2027.     if (OutReq->Overlapped == NULL) {
  2028.         ChatSysError("malloc()",
  2029.                      "DoOverlappedEventSend()",
  2030.                      TRUE);
  2031.     }
  2032.     Buffers = &OutReq->Buffer;
  2033.  
  2034.     OutReq->Overlapped->hEvent =
  2035.       (WSAEVENT)CreateEvent(NULL,
  2036.                             FALSE,
  2037.                             FALSE,
  2038.                             NULL);
  2039.     if (OutReq->Overlapped->hEvent == NULL) {
  2040.         ChatSysError("CreateEvent()",
  2041.                      "DoOverlappedEventSend()",
  2042.                      TRUE);
  2043.     }
  2044.  
  2045.     // Do the send.
  2046.     Error = WSASend(ConnData->Socket,
  2047.                     Buffers,
  2048.                     1,
  2049.                     &BytesSent,
  2050.                     0,
  2051.                     OutReq->Overlapped,
  2052.                     NULL);
  2053.  
  2054.     if (Error == SOCKET_ERROR) {
  2055.  
  2056.         // There is an error...
  2057.         Errno = WSAGetLastError();
  2058.         if (Errno == WSAEWOULDBLOCK) {
  2059.  
  2060.             // WSAEWOULDBLOCK means we have to wait for an FD_WRITE
  2061.             // before we can send.
  2062.             ConnData->WriteOk = FALSE;
  2063.             ReturnValue = CHAT_WOULD_BLOCK;
  2064.  
  2065.         } else if (Errno == WSA_IO_PENDING) {
  2066.  
  2067.             // Overlapped send successfully initiated.
  2068.             // Increase the event count, and update the event and
  2069.             // output request arrays to hold the entries for this
  2070.             // overlapped send.
  2071.             ConnData->NumEvents++;
  2072.             if (ConnData->NumEvents > WSA_MAXIMUM_WAIT_EVENTS) {
  2073.  
  2074.                 // We're trying to wait on too many events at
  2075.                 // once.  It's very unlikely this could happen --
  2076.                 // you'd have to get about 62 overlapped sends, in
  2077.                 // row, before one of them is completed and
  2078.                 // signaled.  So just return CHAT_ERROR which will
  2079.                 // break the connection.
  2080.                 ReturnValue = CHAT_ERROR;
  2081.  
  2082.             } else {
  2083.  
  2084.                 ConnData->EventArray[ConnData->NumEvents - 1] =
  2085.                   OutReq->Overlapped->hEvent;
  2086.  
  2087.                 ConnData->OutReqArray[ConnData->NumEvents - 1] = OutReq;
  2088.                 ReturnValue = CHAT_OK;
  2089.             }
  2090.         } // else if (...)
  2091.         else {
  2092.  
  2093.             // An unexpected error occurred.
  2094.             ReturnValue = CHAT_ERROR;
  2095.         }
  2096.  
  2097.     } // if (Error == SOCKET_ERROR)
  2098.  
  2099.     // No error -- the I/O request was completed immediately...
  2100.     ReturnValue = CHAT_OK;
  2101.  
  2102.     return(ReturnValue);
  2103.  
  2104. } // DoOverlappedEventSend()
  2105.  
  2106.  
  2107.  
  2108.  
  2109.  
  2110. int
  2111. DoSend(
  2112.     IN POUTPUT_REQUEST OutReq,
  2113.     IN PCONNDATA       ConnData)
  2114.  
  2115. /*++
  2116.  
  2117. Routine Description:
  2118.  
  2119.     Sends a buffer of data over a connected socket.
  2120.  
  2121. Implementation:
  2122.  
  2123.     This function uses the information contained in the output request
  2124.     structure to determine whether to use overlapped or non-overlapped
  2125.     I/O.  If using overlapped I/O, it calls an appropriate function
  2126.     depending on whether the symbol CALLBACK_NOTIFICATION has been
  2127.     defined. Otherwise, the non-overlapped send in performed
  2128.     immediately.
  2129.  
  2130. Arguments:
  2131.  
  2132.     OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
  2133.     output request.
  2134.  
  2135.     ConnData -- Supplies a pointer to a CONNDATA structure, which
  2136.     identifies a Chat connection.
  2137.  
  2138. Return Value:
  2139.  
  2140.     CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
  2141.  
  2142.     CHAT_ERROR -- A unexpected error occurred.
  2143.  
  2144.     CHAT_OK -- The send was successfully initiated.  If the send was
  2145.     overlapped, either a callback function is forthcoming or another
  2146.     event was placed in the ConnData->EventArray for IOThreadFunc to
  2147.     wait on until it's signaled by WinSock 2.
  2148.  
  2149. --*/
  2150.  
  2151. {
  2152.     int             Size = 0;      // how many bytes we send
  2153.     int             Error;         // return value of WSASend
  2154.     int             Errno;         // result of WSAGetLastError
  2155.     WSABUF          Buffers[1];    // points to the data to be sent
  2156.     DWORD           BytesSent;     // needed in WSASend
  2157.     int             ReturnValue;   // the return value
  2158.  
  2159.     if (OutReq->Type == NON_OVERLAPPED_IO) {
  2160.  
  2161.         // Do a non-overlapped send by setting lpOverlapped and
  2162.         // lpCompletionRoutine to NULL.
  2163.         Buffers[0].len = OutReq->Buffer.len;
  2164.         Buffers[0].buf = OutReq->Buffer.buf;
  2165.         Error = WSASend(ConnData->Socket,
  2166.                         Buffers,
  2167.                         1,
  2168.                         &BytesSent,
  2169.                         0,
  2170.                         NULL,
  2171.                         NULL);
  2172.  
  2173.         if (Error == SOCKET_ERROR) {
  2174.  
  2175.             // There's an error...
  2176.             Errno = WSAGetLastError();
  2177.             if (Errno == WSAEWOULDBLOCK) {
  2178.  
  2179.                 //  WSAEWOULDBLOCK means we have to wait for an FD_WRITE
  2180.                 //  before we can send.
  2181.                 ConnData->WriteOk = FALSE;
  2182.                 ReturnValue = CHAT_WOULD_BLOCK;
  2183.  
  2184.             } else {
  2185.  
  2186.                 // It's an unexpected error.
  2187.                 ReturnValue = CHAT_ERROR;
  2188.             }
  2189.         } else {
  2190.  
  2191.             // There's no error.
  2192.             ReturnValue = CHAT_OK;
  2193.             free(OutReq);
  2194.         }
  2195.  
  2196.     } else if (OutReq->Type == OVERLAPPED_IO) {
  2197.  
  2198. #ifdef CALLBACK_NOTIFICATION
  2199.  
  2200.         ReturnValue = DoOverlappedCallbackSend(OutReq, ConnData);
  2201.  
  2202. #else
  2203.  
  2204.         ReturnValue = DoOverlappedEventSend(OutReq, ConnData);
  2205.  
  2206. #endif
  2207.  
  2208.     } else {
  2209.  
  2210.         // Unknown output type...
  2211.         MessageBox(ConnData->ConnectionWindow,
  2212.                    "Unknown output type given to IOThread. Aborting.",
  2213.                    "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  2214.         ReturnValue = CHAT_ERROR;
  2215.     }
  2216.  
  2217.     return(ReturnValue);
  2218.  
  2219. } // DoSend()
  2220.  
  2221.  
  2222.  
  2223.  
  2224.  
  2225. void CALLBACK
  2226. SendCompFunc(
  2227.     IN DWORD           Error,
  2228.     IN DWORD           BytesTransferred,
  2229.     IN LPWSAOVERLAPPED Overlapped,
  2230.     IN DWORD           Flags)
  2231. /*++
  2232.  
  2233. Routine Description:
  2234.  
  2235.     Completion routine called after a successfully initiated overlapped
  2236.     send operation completes; cleans up data structures associated
  2237.     with the send.
  2238.  
  2239. Arguments:
  2240.  
  2241.     Error -- Supplies the completion status for the overlapped
  2242.     operation.
  2243.  
  2244.     BytesTransferred -- Supplies the actual number of bytes sent.
  2245.  
  2246.     Overlapped -- Supplies a pointer to a WSAOVERLAPPED structure.
  2247.     The hEvent field in the structure contains a pointer to the
  2248.     OUTPUT_REQUEST structure associated with this send operation.
  2249.  
  2250.     Flags -- Not yet used.
  2251.  
  2252. Return Value:
  2253.  
  2254.     None
  2255.  
  2256. --*/
  2257.  
  2258. {
  2259.     POUTPUT_REQUEST OutReq; // The output request
  2260.  
  2261.     OutReq = (POUTPUT_REQUEST)(Overlapped->hEvent);
  2262.  
  2263.     if (Error) {
  2264.         MessageBox(NULL,
  2265.                    "Error during overlapped send.",
  2266.                    "Error",
  2267.                    MB_OK | MB_SETFOREGROUND);
  2268.     }
  2269.  
  2270.     // Free the data buffer, the output request structure,  and the
  2271.     // overlapped I/O structure.
  2272.     free(OutReq->Buffer.buf);
  2273.     free(OutReq);
  2274.     free(Overlapped);
  2275.  
  2276. } // SendCompFunc()
  2277.  
  2278.  
  2279.  
  2280.  
  2281.  
  2282. PCONNDATA
  2283. GetConnData(
  2284.     IN HWND ConnectionWindow
  2285.     )
  2286.  
  2287. /*++
  2288.  
  2289. Routine Description:
  2290.  
  2291.     Retrieves a pointer to the PCONNDATA data structure associated
  2292.     with a connection window
  2293.  
  2294. Arguments:
  2295.  
  2296.     ConnectionWindow - Supplies the handle to a connection window.
  2297.  
  2298. Return Value:
  2299.  
  2300.     Returns the PCONNDATA associated with the given connection window
  2301.     handle.
  2302.  
  2303. --*/
  2304.  
  2305. {
  2306.     return((PCONNDATA)GetWindowLong(ConnectionWindow, GWL_CONNINFO));
  2307.  
  2308. } // GetConnData()
  2309.  
  2310.  
  2311.  
  2312.  
  2313.  
  2314. BOOL
  2315. MakeConnection(
  2316.     IN HWND ConnectionWindow)
  2317.  
  2318. /* ++
  2319.  
  2320. Routine Description:
  2321.  
  2322.     Initiates a call to another instance of chat.
  2323.     1) Creates a socket
  2324.     2) Set the socket up for windows message notification of FD_CONNECT
  2325.        events.
  2326.     3) Allocate a buffer for caller name & subject, and fill it in.
  2327.     4) Allocate a buffer to receive callee name.
  2328.     5) Set up quality of service for the connection.
  2329.     6) Attempt a connection
  2330.  
  2331. Arguments:
  2332.  
  2333.     ConnectionWindow - Handle to the window that receives
  2334.     notification when an FD_CONNECT event occurs.
  2335.  
  2336. Return Value:
  2337.  
  2338.     TRUE - A connection attempt was successfully initiated.
  2339.  
  2340.     FALSE - Error occurred while attempting to initiate a connection.
  2341.  
  2342. --*/
  2343.  
  2344. {
  2345.     int             ConnectStatus;    // the return value of WSAConnect
  2346.     int             Error;            // gets error values
  2347.     BOOL            ReturnValue;      // holds the return value
  2348.     PCONNDATA       ConnData;         // connection-specific data
  2349.     LPWSABUF        CallerBuffer;     // user data we will send
  2350.     LPWSABUF        CalleeBuffer;     // user data we will receive
  2351.     QOS             QualityOfService; // QOS structure, used by WSAConnect
  2352.     LPFLOWSPEC      FlowSpec;         // dummy pointer for code readability
  2353.     char            MsgText[MSG_LEN]; // holds message strings
  2354.     BOOL            QOSSupported;     // does the protocol support QOS?
  2355.     BOOL            CTDTSupported;    // support for conn-time data xfer?
  2356.     struct sockaddr *SockAddr;        // socket address for WSAConnect
  2357.     int             SockAddrLen;      // the length of the above
  2358.  
  2359.  
  2360.     ReturnValue = TRUE;
  2361.     ConnData = GetConnData(ConnectionWindow);
  2362.     QOSSupported = (ConnData->ProtocolInfo->dwServiceFlags1 &
  2363.                     XP1_QOS_SUPPORTED);
  2364.     CTDTSupported = (ConnData->ProtocolInfo->dwServiceFlags1 &
  2365.                       XP1_CONNECT_DATA);
  2366.     if (CTDTSupported) {
  2367.  
  2368.         // CallerBuffer and CallerBuffer->buf (allocated within the
  2369.         // NameAndSubject dialog box procedure) both get freed by the
  2370.         // end of this function.  CalleeBuffer.buf gets freed upon
  2371.         // connection shutdown -- it needs to be valid after this
  2372.         // function has exited.
  2373.         CallerBuffer = (LPWSABUF)malloc(sizeof(WSABUF));
  2374.         if (CallerBuffer == NULL) {
  2375.             ChatSysError("malloc()",
  2376.                          "MakeConnection()",
  2377.                          TRUE);
  2378.         }
  2379.         CalleeBuffer = &ConnData->CalleeBuffer;
  2380.  
  2381.         // The connection-time data sent back when/if this connection
  2382.         // is accepted will just contain the callee's name.
  2383.         CalleeBuffer->len = NAME_LEN + 1;
  2384.         CalleeBuffer->buf = (char *)malloc(CalleeBuffer->len);
  2385.         if (CallerBuffer->buf == NULL) {
  2386.             ChatSysError("malloc()",
  2387.                          "MakeConnection()",
  2388.                          TRUE);
  2389.         }
  2390.  
  2391.         // Prompt the user for his name and the subject of the call.
  2392.         // a pointer to the CallerBuffer is passed to the dialog box
  2393.         // procedure and the data is packed into this memory.
  2394.         if (!DialogBoxParam(GlobalInstance,
  2395.                             "NameAndSubjectDlg",
  2396.                             ConnectionWindow,
  2397.                             NameAndSubjectDlgProc,
  2398.                             (LPARAM)CallerBuffer)) {
  2399.             ReturnValue = FALSE;
  2400.             goto Done;
  2401.         }
  2402.     } // if (CTDTSupported)
  2403.  
  2404.     // Create a socket for this connection.
  2405.     ConnData->Socket = WSASocket(FROM_PROTOCOL_INFO,
  2406.                                  FROM_PROTOCOL_INFO,
  2407.                                  FROM_PROTOCOL_INFO,
  2408.                                  ConnData->ProtocolInfo,
  2409.                                  0,
  2410.                                  WSA_FLAG_OVERLAPPED);
  2411.  
  2412.     if (ConnData->Socket == INVALID_SOCKET) {
  2413.  
  2414.         MessageBox(ConnectionWindow, "Could not open a socket.", "Error",
  2415.                    MB_OK | MB_SETFOREGROUND);
  2416.         ReturnValue = FALSE;
  2417.         goto Done;
  2418.  
  2419.     } else {
  2420.  
  2421.         // Set up socket for windows message event notification.
  2422.         WSAAsyncSelect(ConnData->Socket,
  2423.                        ConnectionWindow,
  2424.                        USMSG_CONNECT,
  2425.                        FD_CONNECT);
  2426.     }
  2427.  
  2428.     if (QOSSupported) {
  2429.  
  2430.         // Set  up  quality  of  service  info  we  want.   Do  not include any
  2431.         // provider-specific information.
  2432.         QualityOfService.ProviderSpecific.len = 0;
  2433.         QualityOfService.ProviderSpecific.buf = NULL;
  2434.  
  2435.         // FlowSpec is used only to make this code more readable.
  2436.         FlowSpec = & QualityOfService.SendingFlowspec;
  2437.         FlowSpec->TokenRate = TOKENRATE;
  2438.         FlowSpec->TokenBucketSize = QOS_UNSPECIFIED;
  2439.         FlowSpec->PeakBandwidth = QOS_UNSPECIFIED;
  2440.         FlowSpec->Latency = QOS_UNSPECIFIED;
  2441.         FlowSpec->DelayVariation = QOS_UNSPECIFIED;
  2442.         FlowSpec->ServiceType = SERVICETYPE_BESTEFFORT;
  2443.  
  2444.         // again, the extra FlowSpec variable is for readability
  2445.         FlowSpec = & QualityOfService.ReceivingFlowspec;
  2446.         FlowSpec->TokenRate = TOKENRATE;
  2447.         FlowSpec->TokenBucketSize = QOS_UNSPECIFIED;
  2448.         FlowSpec->PeakBandwidth = QOS_UNSPECIFIED;
  2449.         FlowSpec->Latency = QOS_UNSPECIFIED;
  2450.         FlowSpec->DelayVariation = QOS_UNSPECIFIED;
  2451.         FlowSpec->ServiceType = SERVICETYPE_BESTEFFORT;
  2452.     }
  2453.  
  2454.     // Reminder: WinSock 2 requires that we pass a struct sockaddr *
  2455.     // to WSAConnect; however, the service provider is free to
  2456.     // interpret the pointer as an arbitrary chunk of data of size
  2457.     // SockAddrLen.
  2458.     SockAddr = (struct sockaddr *)ConnData->RemoteSockAddr.buf;
  2459.     SockAddrLen = ConnData->RemoteSockAddr.len;
  2460.  
  2461.  
  2462.     // Try to connect; depending on whether QOS or Connection Time
  2463.     // Data Transfer are supported, pass the appropriate data.
  2464.     if (QOSSupported && CTDTSupported) {
  2465.  
  2466.         // Both are supported...
  2467.         ConnectStatus = WSAConnect(ConnData->Socket,
  2468.                                    SockAddr,
  2469.                                    SockAddrLen,
  2470.                                    CallerBuffer,
  2471.                                    CalleeBuffer,
  2472.                                    &QualityOfService,
  2473.                                    NULL);
  2474.     } else if (!QOSSupported && CTDTSupported) {
  2475.  
  2476.         // Only CTDT is supported...
  2477.         ConnectStatus = WSAConnect(ConnData->Socket,
  2478.                                    SockAddr,
  2479.                                    SockAddrLen,
  2480.                                    CallerBuffer,
  2481.                                    CalleeBuffer,
  2482.                                    NULL,
  2483.                                    NULL);
  2484.  
  2485.     } else if (QOSSupported && !CTDTSupported) {
  2486.         // Only QOS is supported...  case for ATM
  2487.         ConnectStatus = WSAConnect(ConnData->Socket,
  2488.                                    SockAddr,
  2489.                                    SockAddrLen,
  2490.                                    NULL,
  2491.                                    NULL,
  2492.                                    &QualityOfService,
  2493.                                    NULL);
  2494.     } else {
  2495.  
  2496.         // Neither is supported...   case for TCP
  2497.         ConnectStatus = WSAConnect(ConnData->Socket,
  2498.                                    SockAddr,
  2499.                                    SockAddrLen,
  2500.                                    NULL,
  2501.                                    NULL,
  2502.                                    NULL,
  2503.                                    NULL);
  2504.     }
  2505.  
  2506.     // Check for errors.
  2507.     if (ConnectStatus == SOCKET_ERROR) {
  2508.         Error = WSAGetLastError();
  2509.         if (Error != WSAEWOULDBLOCK) {
  2510.             wsprintf(MsgText, "WSAConnect failed.  Error code: %d",
  2511.                      Error);
  2512.             MessageBox(ConnectionWindow, MsgText, "Error",
  2513.                        MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  2514.             ReturnValue = FALSE;
  2515.         }
  2516.     } else {
  2517.         MessageBox(ConnectionWindow,
  2518.                    "WSAConnect should have returned SOCKET_ERROR.",
  2519.                    "Error", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
  2520.         ReturnValue = FALSE;
  2521.     }
  2522.  
  2523.  Done:
  2524.     // Free allocated memory, except CalleeBuffer which will be
  2525.     // freed when connection window is destroyed.
  2526.     if (CTDTSupported) {
  2527.         free(CallerBuffer->buf);
  2528.         free(CallerBuffer);
  2529.     }
  2530.     return(ReturnValue);
  2531. } // MakeConnection()
  2532.  
  2533.  
  2534.  
  2535.  
  2536.  
  2537. BOOL
  2538. FillInFamilies(
  2539.     IN HWND  DialogWindow,
  2540.     IN DWORD FamilyLB)
  2541. /*++
  2542.  
  2543. Routine Description:
  2544.  
  2545.     Fills in the listbox with a string for each protocol on which Chat
  2546.     has a listening socket.
  2547.  
  2548. Implementation:
  2549.  
  2550.     For each socket in the ListeningSockets array, this function:
  2551.  
  2552.         1. Gets the associated protocol information structure.
  2553.  
  2554.         2. If Chat recognizes the address family, it prints it in a
  2555.         string; if not, it prints "unknown".
  2556.  
  2557.         3. In the second half of the string, prints out the
  2558.         human-readable string contained in the protocol information.
  2559.  
  2560.         4. Sends the string to be an entry in the listbox identified
  2561.         by FamilyLB.
  2562.  
  2563. Arguments:
  2564.  
  2565.     DialogWindow -- Window handle for the dialog box.
  2566.  
  2567.     FamilyLB -- Integer identifier for a listbox in the dialog box.
  2568.  
  2569. Return Value:
  2570.  
  2571.     TRUE - All messages were successfully sent to the listbox.
  2572.  
  2573.     FALSE - An LB_ADDSTRING message failed.
  2574.  
  2575. --*/
  2576.  
  2577. {
  2578.  
  2579.     int     i;                 // counting variable
  2580.     LRESULT Result;            // result of SendMessage calls
  2581.     char    LBString[MSG_LEN]; // string to send to the listbox
  2582.     int     Offset;             // index into the string
  2583.  
  2584.     // Iterate through all members of the ListeningSockets array.
  2585.     for (i = 0; i < NumFound; i++){
  2586.  
  2587.         // We are prepending a number to the list box string to be displayed
  2588.         // since the list box does us the favor of alphabetizing the
  2589.         // the sting and we are depending on the list entries appearing in the
  2590.         // list box in the order that we added them to the list.
  2591.  
  2592.         Offset = wsprintf(LBString, "%02i ",i);
  2593.  
  2594.         switch (ListeningSockets[i].ProtocolInfo->iAddressFamily) {
  2595.  
  2596.             case AF_INET:
  2597.  
  2598.                 Offset += wsprintf(LBString+Offset, "INET/");
  2599.                 wsprintf(LBString + Offset, "%s",
  2600.                          ListeningSockets[i].ProtocolInfo->szProtocol);
  2601.                 Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
  2602.                                      LB_ADDSTRING, 0, (LPARAM)LBString);
  2603.                 break;
  2604.  
  2605.             case AF_ATM:
  2606.                 Offset += wsprintf(LBString+Offset, "ATM/");
  2607.                 wsprintf(LBString + Offset, "%s",
  2608.                          ListeningSockets[i].ProtocolInfo->szProtocol);
  2609.                 Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
  2610.                                      LB_ADDSTRING, 0, (LPARAM)LBString);
  2611.                 break;
  2612.  
  2613.             case AF_IPX:
  2614.                 Offset += wsprintf(LBString+Offset, "IPX/");
  2615.                 wsprintf(LBString + Offset, "%s",
  2616.                          ListeningSockets[i].ProtocolInfo->szProtocol);
  2617.                 Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
  2618.                                      LB_ADDSTRING, 0, (LPARAM)LBString);
  2619.                 break;
  2620.  
  2621.             case AF_NETBIOS:
  2622.                 Offset += wsprintf(LBString+Offset, "NETBIOS/");
  2623.                 wsprintf(LBString + Offset, "%s",
  2624.                          ListeningSockets[i].ProtocolInfo->szProtocol);
  2625.                 Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
  2626.                                      LB_ADDSTRING, 0, (LPARAM)LBString);
  2627.                 break;
  2628.             default:
  2629.  
  2630.                 Offset += wsprintf(LBString+ Offset, "(unknown)/");
  2631.                 wsprintf(LBString + Offset, "%s",
  2632.                          ListeningSockets[i].ProtocolInfo->szProtocol);
  2633.                 Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
  2634.                                      LB_ADDSTRING, 0, (LPARAM)LBString);
  2635.                 break;
  2636.  
  2637.         }
  2638.         if ((Result == LB_ERR) || (Result == LB_ERRSPACE)) {
  2639.             return(FALSE);
  2640.         }
  2641.     }
  2642.     return(TRUE);
  2643.  
  2644. } // FillInFamilies()
  2645.  
  2646.  
  2647.  
  2648.  
  2649.  
  2650. LPWSAPROTOCOL_INFO
  2651. GetProtoFromIndex(
  2652.     IN int LBIndex)
  2653. /*++
  2654.  
  2655. Routine Description:
  2656.  
  2657.     Takes an index into the ChooseFamily dialog box and returns the
  2658.     protocol associated with that index. This works because when the
  2659.     dialog box is set up, the strings representing the protocols are
  2660.     added to the listbox in the order they fall in ListeningSockets.
  2661.  
  2662. Arguments:
  2663.  
  2664.     LBIndex -- The index of the user's selection.
  2665.  
  2666. Return Value:
  2667.  
  2668.     NULL -- The index doesn't correspond to an element in the
  2669.     ListeningSockets array.
  2670.  
  2671.     LPWSAPROTOCOL_INFO -- A pointer to the protocol information struct
  2672.     corresponding to LBIndex.
  2673.  
  2674. --*/
  2675. {
  2676.     if (LBIndex > (NumFound - 1)) {
  2677.         return(NULL);
  2678.     }
  2679.     return(ListeningSockets[LBIndex].ProtocolInfo);
  2680.  
  2681. } // GetProtoFromIndex()
  2682.  
  2683.  
  2684.  
  2685.  
  2686.  
  2687. LPWSAPROTOCOL_INFO
  2688. GetProtoFromSocket(
  2689.     IN SOCKET Socket)
  2690. /*++
  2691.  
  2692. Routine Description:
  2693.  
  2694.     Searches the ListeningSockets array for the first entry with a
  2695.     Socket field equal to the Socket parameter.  When found, it
  2696.     returns a pointer to the associated protocol information
  2697.     structure.  If not found, return NULL.
  2698.  
  2699. Arguments:
  2700.  
  2701.     Socket -- The socket who's associated WSAPROTOCOL_INFO struct we are
  2702.     looking for.
  2703.  
  2704. Return Value:
  2705.  
  2706.     NULL -- The socket was not found in the ListeningSockets array.
  2707.  
  2708.     LPWSAPROTOCOL_INFO -- A pointer to the protocol information struct
  2709.     for the socket.
  2710.  
  2711. --*/
  2712. {
  2713.  
  2714.     int i; // counting variable
  2715.  
  2716.     for (i = 0; i < NumFound; i++) {
  2717.         if (ListeningSockets[i].Socket == Socket) {
  2718.             return(ListeningSockets[i].ProtocolInfo);
  2719.         }
  2720.     }
  2721.     return(NULL);
  2722.  
  2723. } // GetProtoFromSocket()
  2724.  
  2725.  
  2726.  
  2727.  
  2728.  
  2729. void
  2730. CleanupConnection(
  2731.     IN PCONNDATA ConnData)
  2732. /*++
  2733.  
  2734. Routine Description:
  2735.  
  2736.     Frees all memory and objects allocated for this connection.
  2737.  
  2738. Arguments:
  2739.  
  2740.     ConnData -- Pointer to the connection-specific data structure.
  2741.  
  2742. Return Value:
  2743.  
  2744.     None.
  2745.  
  2746. --*/
  2747. {
  2748.  
  2749.     // Clean up connection-specific data.  To keep this code
  2750.     // readable, we ignore any errors.
  2751.     if (ConnData->SocketEventObject != NULL) {
  2752.         CloseHandle(ConnData->SocketEventObject);
  2753.         ConnData->SocketEventObject = NULL;
  2754.     }
  2755.     if (ConnData->OutputEventObject != NULL) {
  2756.         CloseHandle(ConnData->OutputEventObject);
  2757.         ConnData->OutputEventObject = NULL;
  2758.     }
  2759.     if (ConnData->OutputQueue != NULL) {
  2760.         QFree(ConnData->OutputQueue);
  2761.         ConnData->OutputQueue = NULL;
  2762.     }
  2763.     if (ConnData->IOThreadHandle != NULL) {
  2764.         CloseHandle(ConnData->IOThreadHandle);
  2765.         ConnData->IOThreadHandle = NULL;
  2766.     }
  2767.     if (ConnData->Socket != INVALID_SOCKET) {
  2768.         closesocket(ConnData->Socket);
  2769.     }
  2770.     if (ConnData->RemoteSockAddr.buf != NULL) {
  2771.         free(ConnData->RemoteSockAddr.buf);
  2772.         ConnData->RemoteSockAddr.buf = NULL;
  2773.     }
  2774.     if (ConnData->CalleeBuffer.buf != NULL) {
  2775.         free(ConnData->CalleeBuffer.buf);
  2776.         ConnData->CalleeBuffer.buf = NULL;
  2777.     }
  2778.     free(ConnData);
  2779.  
  2780. } // CleanupConnection()
  2781.